#ifndef __WIZ_UTILS_RTTI_HPP__SHANHAOBO_19800429__
#define __WIZ_UTILS_RTTI_HPP__SHANHAOBO_19800429__

#include "./Factory/WizUtilsFactory.hpp"
#include "../DataType/WizDataTypeName.hpp"

namespace Wiz
{
    namespace RTTI_TypeID
    {
        namespace Core
        {
            class Type
            {
            public:
                Type(::Wiz::String::In CLSName, Type* BaseRTTI) : m_CLSName(CLSName), m_SuperRTTI(BaseRTTI)
                {
                }
            public:
                Type* GetSuperRTTI() const
                {
                    return m_SuperRTTI;
                }
                ::Wiz::String::RefConst GetName() const
                {
                    return m_CLSName;
                }
            protected:
                Type*               m_SuperRTTI;
                ::Wiz::String::Type   m_CLSName;
            };
            WIZ_DECLARE(::Wiz::RTTI_TypeID::Core::Type);
        } /// end of namespace Core

        namespace Null
        {
            struct Type
            {
                static ::Wiz::RTTI_TypeID::Core::Ptr GetMyRTTI()
                {
                    return WIZ_NULLPTR;
                }
            };
        } /// end of namespace Null

        template<class BaseOfT = ::Wiz::RTTI_TypeID::Null::Type>
        class Type : public BaseOfT
        {
        public:
            Type()
            {}
        public:
            static ::Wiz::String::RefConst GetRTTIName()
            {
                return GetMyRTTI()->GetName();
            }
            static ::Wiz::RTTI_TypeID::Core::Ptr GetMyRTTI()
            {
                static ::Wiz::RTTI_TypeID::Core::Type s_RTTI(::Wiz::String::Type(typeid(Type).name()), BaseOfT::GetMyRTTI());
                return &s_RTTI;
            }
            virtual ::Wiz::RTTI_TypeID::Core::Ptr GetRealRTTI() const
            {
                return GetMyRTTI();
            }
        public:
            /// Tests if this class is derived from a specific class(or is that type itself);
            ::Wiz::Bool::Type IsKindOf(const Type& Other) const
            {
                WIZ_ASSERT(::Wiz::IsValidPtr(GetRealRTTI()));
                WIZ_ASSERT(::Wiz::IsValidPtr(Other.GetRealRTTI()));

                ::Wiz::RTTI_TypeID::Core::Ptr CoreRTTIPtr = Other.GetRealRTTI();
                ::Wiz::RTTI_TypeID::Core::Ptr thisRTTIPtr = GetRealRTTI();
                while (thisRTTIPtr != CoreRTTIPtr)
                {
                    thisRTTIPtr = thisRTTIPtr->GetSuperRTTI();
                    if (::Wiz::NotValidPtr(thisRTTIPtr))
                    {
                        return ::Wiz::Bool::False;
                    }
                }

                return ::Wiz::Bool::True;
            }

            template<class U>
            ::Wiz::Bool::Type IsKindOf() const
            {
                WIZ_ASSERT(::Wiz::IsValidPtr(GetRealRTTI()));
                WIZ_ASSERT(::Wiz::IsValidPtr(U::GetMyRTTI()));

                ::Wiz::RTTI_TypeID::Core::Ptr CoreRTTIPtr = U::GetMyRTTI();
                ::Wiz::RTTI_TypeID::Core::Ptr thisRTTIPtr = GetRealRTTI();
                while (thisRTTIPtr != CoreRTTIPtr)
                {
                    thisRTTIPtr = thisRTTIPtr->GetSuperRTTI();
                    if (::Wiz::NotValidPtr(thisRTTIPtr))
                    {
                        return ::Wiz::Bool::False;
                    }
                }

                return ::Wiz::Bool::True;
            }

            /// Tests if this class is a specific type.
            ::Wiz::Bool::Type IsA(const Type& Other) const
            {
                WIZ_ASSERT(::Wiz::IsValidPtr(GetRealRTTI()));
                WIZ_ASSERT(::Wiz::IsValidPtr(Other.GetRealRTTI()));

                return Other.GetRealRTTI() == GetRealRTTI();
            }

            template<class U>
            ::Wiz::Bool::Type IsA() const
            {
                WIZ_ASSERT(::Wiz::IsValidPtr(GetRealRTTI()));
                WIZ_ASSERT(::Wiz::IsValidPtr(U::GetMyRTTI()));

                return U::GetMyRTTI() == GetRealRTTI();
            }
        };
    } /// end of namespace RTTI
} /// end of namespace Wiz

#endif /*__WIZ_UTILS_RTTI_HPP__SHANHAOBO_19800429__*/
